/* @flow */

import config from '../config'
import { initUse } from './use'
import { initMixin } from './mixin'
import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
import { ASSET_TYPES } from 'shared/constants'
import builtInComponents from '../components/index'
import { observe } from 'core/observer/index'

import {
  warn,
  extend,
  nextTick,
  mergeOptions,
  defineReactive
} from '../util/index'

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config // configDef 有一个get方法 返回 config
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = () => { // 如果是开发环境 再加一个set方法
      warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      )
    }
  }

  // 初始化Vue.config 对象 并且会在 platforms/web/runtime/index.js 中给config赋值
  Object.defineProperty(Vue, 'config', configDef)

  // exposed util methods.
  // NOTE: these are not considered part of the public API - avoid relying on
  // them unless you are aware of the risk.
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set // 向Vue的原型上注册set delete 和 nextTick 
  Vue.delete = del
  Vue.nextTick = nextTick

  // 2.6 explicit observable API
  Vue.observable = <T>(obj: T): T => { // observable 可以设置双向绑定数据
    observe(obj)
    return obj
  }

  // 将 Vue.options 设置为一个对象 并且该对象的原型 =null; 原型为null可以提高性能
  // ASSET_TYPES 里面有 component filter directive 三个值
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => { // 遍历然后加上s后作为Vue.options的key 也赋值为对象
    Vue.options[type + 's'] = Object.create(null)
  })

  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex's multi-instance scenarios.
  Vue.options._base = Vue

  // extend 的作用是把第二个参数的属性复制到第一个参数中 是浅拷贝 有点相对于 Object.assign
  // 这里是注册内置组件 keep-alive
  extend(Vue.options.components, builtInComponents)

  initUse(Vue) // 注册 Vue.use() 用来注册插件
  initMixin(Vue) // 注册 Vue.mixin() 用来实现混入
  initExtend(Vue) // 注册 Vue.extend() 基于传入的options返回一个组件的构造函数
  initAssetRegisters(Vue) // 注册 Vue.directive() Vue.component() Vue.filter()
}
